<!doctype html>
<html>
    <head>
        <title>连线类型手册 - HT for Web</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="user-scalable=yes, width=1024">
        <style type="text/css">
            h1, h2, h3, h4, h5, h6, p, blockquote {
                margin: 0;
                padding: 0;
            }
            body {
                font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif;
                font-size: 13px;
                line-height: 18px;
                color: #737373;
                background-color: white;
                margin: 10px 13px 10px 13px;
            }
            table {
                margin: 10px 0 15px 0;
                border-collapse: collapse;
            }
            td,th {
                border: 1px solid #ddd;
                padding: 3px 10px;
            }
            th {
                padding: 5px 10px;
            }
            a {
                color: #0069d6;
            }
            a:hover {
                color: #0050a3;
                text-decoration: none;
            }
            a img {
                border: none;
            }
            p {
                margin-bottom: 9px;
            }
            h1, h2, h3, h4, h5, h6 {
                color: #404040;
                line-height: 36px;
            }
            h1 {
                margin-bottom: 18px;
                font-size: 30px;
            }
            h2 {
                font-size: 24px;
            }
            h3 {
                font-size: 18px;
            }
            h4 {
                font-size: 16px;
            }
            h5 {
                font-size: 14px;
            }
            h6 {
                font-size: 13px;
            }
            hr {
                margin: 0 0 19px;
                border: 0;
                border-bottom: 1px solid #ccc;
            }
            blockquote {
                padding: 13px 13px 21px 15px;
                margin-bottom: 18px;
                font-family:georgia,serif;
                font-style: italic;
            }
            blockquote:before {
                content:"\201C";
                font-size:40px;
                margin-left:-10px;
                font-family:georgia,serif;
                color:#eee;
            }
            blockquote p {
                font-size: 14px;
                font-weight: 300;
                line-height: 18px;
                margin-bottom: 0;
                font-style: italic;
            }
            code, pre {
                font-family: Monaco, Andale Mono, Courier New, monospace;
            }
            code {
                background-color: #fee9cc;
                color: rgba(0, 0, 0, 0.75);
                padding: 1px 3px;
                font-size: 12px;
                -webkit-border-radius: 3px;
                -moz-border-radius: 3px;
                border-radius: 3px;
            }
            pre {
                display: block;
                padding: 14px;
                margin: 0 0 18px;
                line-height: 16px;
                font-size: 11px;
                border: 1px solid #d9d9d9;
                white-space: pre-wrap;
                word-wrap: break-word;
            }
            pre code {
                background-color: #fff;
                color:#737373;
                font-size: 11px;
                padding: 0;
            }
            sup {
                font-size: 0.83em;
                vertical-align: super;
                line-height: 0;
            }
            * {
                -webkit-print-color-adjust: exact;
            }
            @media screen and (min-width: 914px) {
                body {
                    width: 854px;
                    margin:10px auto;
                }
            }
            @media print {
                body,code,pre code,h1,h2,h3,h4,h5,h6 {
                    color: black;
                }
                table, pre {
                    page-break-inside: avoid;
                }
            }
            iframe{
                width: 100%;
                border: 1px solid #34495E;
                margin: 0;
            }
            .logo{
                vertical-align: middle;
            }

        </style>
        <script>
            function init() {
                var logoSrc = '',
                    logos = document.querySelectorAll('.logo'),
                    i = 0;
                for (; i < logos.length; i++) {
                    logos[i].src = logoSrc;
                }

                var iframes = document.querySelectorAll('iframe'),
                    func = function(){};
                for (i=0; i < iframes.length; i++) {
                    var iframe = iframes[i];

                    // a small hack to make it work on android
                    iframe.ontouchstart = func;

                    if (window.location && window.location.hostname && window.location.hostname.indexOf('hightopo') >= 0) {
                        var div = document.createElement('div');
                        div.style.float = 'left';
                        div.innerHTML = '<a href="https://hightopo.com/codeeditor/index.html?url=' + iframe.contentWindow.location.pathname + '" target="_blank">在线编辑</a>';
                        iframe.parentNode.insertBefore(div, iframe);

                        var div = document.createElement('div');
                        div.style.float = 'left';
                        div.innerHTML = '&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;';
                        iframe.parentNode.insertBefore(div, iframe);
                    }

                    var div = document.createElement('div');
                    div.innerHTML = '<a href="' + iframe.src + '" target="_blank">独立运行→</a>';
                    iframe.parentNode.insertBefore(div, iframe);
                }
            }
        </script>
    </head>
    <body onload="init();">
        <a href="http://www.hightopo.com"><img class="logo"></a>HT for Web 连线类型手册
        <hr style="margin: 1px 0 20px 0">
<p>索引</p>

<ul><li><a href="#ref_overview">概述</a> </li><li><a href="#ref_custom">自定义</a></li><li><a href="#ref_edgetype">连线类型</a></li><li><a href="#ref_edgearrow">连线箭头</a></li><li><a href="#ref_complexedge">复杂连线</a></li></ul>

<hr/>

<div id="ref_overview"></div>

<h2>概述</h2>

<p><code>HT for Web</code>提供了默认的直线和多点的连线类型能满足大部分基本拓扑图形应用，但对于绘制流程图、组织结构图和思维导图等应用来说还需要更多类型的连线，
为此<code>HT for Web</code>提供了能满足更多应用需求的连线类型扩展库。</p>

<p>使用本章节介绍的连线类型需要在引入<code>ht.js</code>核心库之后，再引入一个<code>ht-edgetype.js</code>的连线类型插件库。</p>

<div id="ref_custom"></div>

<h2>自定义</h2>

<p><code>ht.Default.setEdgeType(type, func, mutual)</code>函数可用于自定义新连线类型：</p>

<ul><li><code>type</code>：字符串类型的连线类型，对应<code>style</code>的<code>edge.type</code>属性</li><li><code>func</code>：函数类型，根据传入参数<code>(edge, gap, graphView, sameSourceWithFirstEdge)</code>返回连线走向信息<ul><li><code>edge</code>：当前连线对象</li><li><code>gap</code>：多条连线成捆时，本连线对象对应中心连线的间距  </li><li><code>graphView</code>：当前对应拓扑组件对象  </li><li><code>sameSourceWithFirstEdge</code>：<code>boolean</code>类型，该连线是否与同组的第一条连线同源</li><li>返回值为<code>{points: new ht.List(...), segments: new ht.List(...)}</code>结构的连线走向信息，<code>segments</code>可取值如下：<ul><li>1: <code>moveTo</code>，占用<code>1</code>个点信息</li><li>2: <code>lineTo</code>，占用<code>1</code>个点信息</li><li>3: <code>quadraticCurveTo</code>，占用<code>2</code>个点信息</li><li>4: <code>bezierCurveTo</code>，占用<code>3</code>个点信息</li><li>5: <code>closePath</code>，不占用点信息</li></ul></li></ul></li><li><code>mutual</code>：该参数决定连线是否影响起始或结束节点上的所有连线，默认为<code>false</code>代表只影响同<code>source</code>和<code>target</code>的<code>EdgeGroup</code>中的连线，
<code>HT</code>预定义的连线类型中，后缀为<code>2</code>的类型都是<code>mutual</code>为<code>true</code>的复杂连线类型，参见<a href="#ref_complexedge">复杂连线</a>章节</li></ul>

<p><iframe src="examples/example_custom.html" style="height:310px"></iframe></p>

<pre><code>ht.Default.setEdgeType(&#39;custom&#39;, function(edge, gap, graphView, sameSourceWithFirstEdge){
    var sourcePoint = edge.getSourceAgent().getPosition(),
        targetPoint = edge.getTargetAgent().getPosition(),
        points = new ht.List();       
        points.add(sourcePoint);
        points.add({
            x: (sourcePoint.x + targetPoint.x)/2, 
            y: (sourcePoint.y + targetPoint.y)/2 + 300
        });                  
        points.add(targetPoint);                                                       

    return {
        points: points,
        segments: new ht.List([1, 3])
    };                 
});  </code></pre>

<p>以上自定义连线例子中，对连线在sourcePoint和targetPoint之间，插入一个中心控制点作为曲线的拐点。</p>

<p>该例子运用了<code>graphView.setLayers([&#39;nodeLayer&#39;, &#39;edgeLayer&#39;]);</code>的分层功能，
通过<code>node.setLayer(&#39;nodeLayer&#39;);</code>和<code>edge.setLayer(&#39;edgeLayer&#39;);</code>分别将<code>Node</code>和<code>Edge</code>归入不同的图层，
因为默认节点会显示在连线之上，通过这样的分层后节点会呈现在连线之下。</p>

<p>鼠标移动到连线之上是会动态改变连线颜色，该功能是通过直接对<code>GraphView.getView()</code>添加<code>mousemove</code>事件做的特殊处理，
<code>ht.Default.isDragging()</code>的判断是为了避免在移动节点时进行处理，通过<code>graphView.getDataAt(e);</code>可获取当前鼠标所在位置下图元。</p>

<pre><code>var lastFocus = null;
graphView.getView().addEventListener(&#39;mousemove&#39;, function(e){ 
    if(!ht.Default.isDragging()){
        if(lastFocus){
            lastFocus.s(&#39;edge.color&#39;, &#39;lightgray&#39;);
        }                        
        var data = graphView.getDataAt(e);                        
        if(data instanceof ht.Edge){                            
            data.s(&#39;edge.color&#39;, &#39;red&#39;);
            lastFocus = data;                            
        }else{                            
            lastFocus = null;                            
        }                        
    }                    
});</code></pre>

<div id="ref_edgetype"></div>

<h2>连线类型</h2>

<p>连线类型扩展包预定义了如下可选择类型：</p>

<ul><li><code>boundary</code>：该类型的连线仅连接到图元矩形边缘</li><li><code>ripple</code>：该类型呈现波浪效果连线<ul><li><code>edge.offset</code>：指定制连线距离图元中心位置</li><li><code>edge.ripple.size</code>：指定波浪的起伏次数，默认为<code>1</code></li><li><code>edge.ripple.length</code>：指定波浪的长度，该属性优先级高于<code>edge.ripple.size</code></li><li><code>edge.ripple.both</code>：指定是否双边起伏，默认为<code>false</code></li><li><code>edge.center</code>：指定起始和结束点是否聚合，默认为<code>false</code></li><li><code>edge.ripple.elevation</code>：指定波浪起伏的高度，默认为<code>-20</code></li><li><code>edge.ripple.straight</code>：指定波浪是否为直线，默认为<code>false</code></li></ul></li><li><code>h.v</code>：该类型从起始点先水平再垂直到结束点的走向<ul><li><code>edge.corner.radius</code>：控制拐角曲线弧度</li><li><code>edge.center</code>：默认值为<code>false</code>代表从矩形边缘开始走向，<code>true</code>则起始和结束于中心</li></ul></li><li><code>v.h</code>：该类型从起始点先垂直再水平到结束点的走向<ul><li><code>edge.corner.radius</code>：控制拐角曲线弧度</li><li><code>edge.center</code>：默认值为<code>false</code>代表从矩形边缘开始走向，<code>true</code>则起始和结束于中心    </li></ul></li><li><code>ortho</code>：该类型在连接起始和结束点之间会拐弯出一条中间折线<ul><li><code>edge.ortho</code>：该参数指定中间折线的拐弯位置，默认值为<code>0.5</code>代表从中间拐弯</li><li><code>edge.corner.radius</code>：控制拐角曲线弧度</li><li><code>edge.center</code>：默认值为<code>false</code>代表从矩形边缘开始走向，<code>true</code>则起始和结束于中心</li></ul></li><li><code>flex</code>：该类型在连接起始和结束的刚开始位置会有一次拐弯<ul><li><code>edge.flex</code>：该参数指定拐弯的位置，默认值为<code>20</code>  </li><li><code>edge.corner.radius</code>：控制拐角曲线弧度</li><li><code>edge.center</code>：默认值为<code>false</code>代表从矩形边缘开始走向，<code>true</code>则起始和结束于中心</li></ul></li><li><code>extend.east</code>：该类型连线往东边延伸进行连接<ul><li><code>edge.extend</code>：控制延伸的距离</li><li><code>edge.corner.radius</code>：控制拐角曲线弧度</li><li><code>edge.center</code>：默认值为<code>false</code>代表从矩形边缘开始走向，<code>true</code>则起始和结束于中心</li></ul></li><li><code>extend.west</code>：该类型连线往西边延伸进行连接<ul><li><code>edge.extend</code>：控制延伸的距离</li><li><code>edge.corner.radius</code>：控制拐角曲线弧度</li><li><code>edge.center</code>：默认值为<code>false</code>代表从矩形边缘开始走向，<code>true</code>则起始和结束于中心</li></ul></li><li><code>extend.north</code>：该类型连线往北边延伸进行连接<ul><li><code>edge.extend</code>：控制延伸的距离</li><li><code>edge.corner.radius</code>：控制拐角曲线弧度</li><li><code>edge.center</code>：默认值为<code>false</code>代表从矩形边缘开始走向，<code>true</code>则起始和结束于中心</li></ul></li><li><code>extend.south</code>：该类型连线往南边延伸进行连接<ul><li><code>edge.extend</code>：控制延伸的距离</li><li><code>edge.corner.radius</code>：控制拐角曲线弧度</li><li><code>edge.center</code>：默认值为<code>false</code>代表从矩形边缘开始走向，<code>true</code>则起始和结束于中心</li></ul></li></ul>

<p><iframe src="examples/example_edgetype.html" style="height:570px"></iframe></p>

<div id="ref_edgearrow"></div>

<h2>连线箭头</h2>

<p>以下例子和上面类型模型一致，但对所有连线增加了起始和结束箭头功能，<code>HT</code>未预定义连线箭头功能，用户可通过自定义矢量的方式任意扩展自己所需箭头样式。
以下代码先定义了<code>toArrow</code>的矢量箭头，然后通过旋转<code>rotation: Math.PI</code>实现<code>fromArrow</code>，
最后通过<code>edge.addStyleIcon</code>的函数分别在<code>15</code>和<code>19</code>的左右中心位置设置了两个箭头图标，
其中<code>keepOrien: true</code>需要设置，因为需要让箭头和连线的平行方向保持一致，无需像<code>label</code>的情况那样动态调节。</p>

<p><iframe src="examples/example_edgearrow.html" style="height:570px"></iframe></p>

<pre><code>ht.Default.setImage(&#39;toArrow&#39;, {
    width: 100,
    height: 50,
    comps: [
        {
            type: &#39;shape&#39;,
            points: [2, 25, 30, 25],
            borderWidth: 4,
            borderColor: &#39;rgba(255, 0, 0, 0.9)&#39;
        },
        {
            type: &#39;shape&#39;,
            points: [30, 10, 30, 40, 50, 25, 30, 10],
            background: &#39;rgba(255, 0, 0, 0.9)&#39;,
            borderWidth: 1,
            borderColor: &#39;red&#39;,
            gradient: &#39;spread.vertical&#39;,
            gradientColor: &#39;rgba(255, 255, 255, 0.9)&#39;
        }
    ]
}); 
ht.Default.setImage(&#39;fromArrow&#39;, {
    width: 100,
    height: 50,
    comps: [
        {
            type: &#39;image&#39;,
            name: &#39;toArrow&#39;,
            rect: [0, 0, 100, 50],
            rotation: Math.PI
        }
    ]
}); 

function createEdge(sourceNode, targetNode, count, typeOrStyle){
    var edge;
    for(var i=0; i&lt;count; i++){
        edge = new ht.Edge(sourceNode, targetNode);
        if(typeof typeOrStyle === &#39;object&#39;){
            edge.s(typeOrStyle);
        }else{
            edge.s(&#39;edge.type&#39;, typeOrStyle);                        
        }
        edge.addStyleIcon(&quot;fromArrow&quot;, {
            position: 15,
            keepOrien: true,
            width: 40,
            height: 20,
            names: [&#39;fromArrow&#39;]
        }); 
        edge.addStyleIcon(&quot;toArrow&quot;, {
            position: 19,
            keepOrien: true,
            width: 40,
            height: 20,                        
            names: [&#39;toArrow&#39;]
        }); 
        dataModel.add(edge);
    }
    return edge;
}  </code></pre>

<div id="ref_complexedge"></div>

<h2>复杂连线</h2>

<p>前面介绍的<a href="#ref_edgetype">连线类型</a>能实现同起始和结束节点将连线的成捆布局功能，但这些连线类型布局时并不考虑起始和结束节点不同的连线存在，
因此对于复杂的拓扑图会存在连线互相重叠的问题，为此<code>HT</code>增加了对应的后缀为<code>2</code>的连线类型：<code>ortho2</code>，<code>flex2</code>，<code>extend.north2</code>、
<code>extend.south2</code>、<code>extend.west2</code>，<code>extend.east2</code>，<code>v.h2</code>和<code>h.v2</code>。</p>

<p><iframe src="examples/example_complexedge.html" style="height:600px"></iframe></p>    <hr id="contact" style="margin: 20px 0 1px 0">
    <a href="http://www.hightopo.com"><img class="logo"></a>欢迎交流 <a href="mailto:service@hightopo.com">service@hightopo.com</a>
</body>
</html>
